package org.exteen.parser;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;

public class Attr extends ExprTokensBuilder {

	final String namespace;
    final String key;
    Object value;
    private StringBuilder sb = new StringBuilder();

    private boolean validated;

    Attr(String namespace, String key) {
        this.namespace = namespace;
        this.key = key;
    }

    public boolean isExpression() {
        return value instanceof Expression || value instanceof Object[];
    }

    public Object getValueObject(JexlContext ctx) {
        if (value instanceof String || value instanceof EscapedString) {
            return value;
        }
        if (value instanceof List) {
            return evaluate((List<?>) value, ctx);
        }
        if (value instanceof Expression && ctx != null) {
            return ((Expression) value).evaluate(ctx);
        }
        return null;
    }

    public Object getValue(JexlContext ctx) {
        Object v =  getValueObject(ctx);
        if (v == null) {
            return null;
        } else if (v instanceof EscapedString) {
            return v.toString();
        } else {
            return v;
        }
    }

    private String evaluate(List<?> tokens, JexlContext ctx) {
        StringBuilder sb = new StringBuilder();
        for (Object t: tokens) {
            if (t instanceof String || t instanceof EscapedString) {
                sb.append(t.toString());
            } else if (t instanceof Expression && ctx != null) {
                Object v = ((Expression) t).evaluate(ctx);
                if (v != null) {
                    sb.append(v.toString());
                }
            }
        }
        return sb.toString();
    }

    public String getKey() {
        return key;
    }

    public String getNamespace() {
        return namespace;
    }

    public boolean wasValidated() {
        return validated;
    }

    public void validated() {
        this.validated = true;
    }

    @Override
    void append(char c) {
        sb.append(c);
    }

    @Override
    void appendExpression(Expression expr) {
        flushSb();
        addValue(expr);
    }

    void close() {
        flushSb();
        sb = null;
    }

    private void flushSb() {
        if (sb.length()>0) {
            String str = sb.toString();
            if (str.contains("\"") || str.contains("<") || str.contains(">")) {
                addValue(str);
            } else {
                addValue(new EscapedString(str)); // no ", <, > inside
            }
            sb.setLength(0);
        }
    }

    @SuppressWarnings("unchecked")
    private final void addValue(Object value) {
        if (this.value == null) {
            this.value = value;
        } else {
            List<Object> list;
            if (!(this.value instanceof List)) {
                Object existing = this.value;
                list = new ArrayList<Object>();
                list.add(existing);
                this.value = list;
            } else {
                list = (List<Object>) this.value;
            }
            list.add(value);
        }
    }
}